﻿using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
using System.Linq.Expressions;
using System;
using Newtonsoft.Json.Linq;

namespace Utilities.Validation
{
    public class UniValidate : Controller
    {
        /// <summary>
        ///     规则:({"rules": {"email": {"required": true,"email": true} } })
        /// </summary>
        public DataValidate DataValidate { get; set; }

        /// <summary>
        ///     服务器端错误信息
        /// </summary>
        public string ErrStr { get; set; }

        /// <summary>
        ///     是否通过验证
        /// </summary>
        public bool Checked { get; set; }

        /// <summary>
        ///     生成的前台js代码调用ValidEnd生成。
        /// </summary>
        public MvcHtmlString JsValidate { get; set; }

        /// <summary>
        ///     初始化
        /// </summary>
        public UniValidate()
        {
            Checked = true;
            DataValidate = new DataValidate();
            //Rules = new Dictionary<string, Dictionary<string, object>>();
        }

        /// <summary>
        /// 初始化名称及提示
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="message">提示</param>
        public DataValidate InitName(string name)
        {
            DataValidate.Name = name;
            //DataValidate.Messages = message;
            return DataValidate;
        }
        /// <summary>
        /// 初始化名称及提示
        /// </summary>
        /// <param name="expression">名称</param>
        /// <param name="message">提示</param>
        public DataValidate InitName<T>(Expression<Func<T>> expression)
        {
            return InitName(((MemberExpression) expression.Body).Member.Name);
        }

        /// <summary>
        ///     生成前台javascript代码,必须调用,用于生成JsValidate,验证第一个表单
        /// </summary>
        /// <returns></returns>
        public void ValidEnd()
        {
            ValidEnd("form:first");
            //ViewBag.HtmlValidate = JsValidate;
        }
        /// <summary>
        ///     生成前台javascript代码,必须调用,用于生成JsValidate
        /// </summary>
        /// <param name="formSelector">验证表单的选择器</param>
        /// <returns></returns>
        public void ValidEnd(string formSelector)
        {
            AddStart();
            var js = new StringBuilder();
            js.Append("<script type=\"text/javascript\">");
            js.Append(" $(function () {");
            //js.Append("var opts =");
            //js.Append(JsonConvert.SerializeObject(DataValidate.Opts));
            //js.Append(";");
            js.Append(string.Format("$('{0}').validate({1});", formSelector, JsonConvert.SerializeObject(DataValidate.Opts).Replace("\\\"", "\"").Replace("\"j#", "").Replace("j#\"", ""))); 
            js.Append("});");
            js.Append("</script>");
            JsValidate = new MvcHtmlString(js.ToString());
            //ViewBag.HtmlValidate = JsValidate;
        }

        public void AddStart()
        {
            DataValidate.SetOpts1("errorElement", "span");//错误标签
            DataValidate.SetOpts1("errorClass", "help-inline");//错误样式
            DataValidate.SetOpts1("errorPlacement", @"j#function(error, element) {element.parent().parent().addClass(""error"");error.appendTo(element.parent());}j#");//错误位置，及其他标签样式
            DataValidate.SetOpts1("success", @"j#function(label) {label.parent().parent().removeClass(""error"");}j#");//删除错误样式
        }

        /// <summary>
        ///     验证所有Controllers里调用
        /// </summary>
        /// <returns></returns>
        public bool CheckAll(HttpRequestBase request)
        {
            if (DataValidate.Opts.ContainsKey("rules"))
            {
                foreach (var item in DataValidate.Opts["rules"] as Dictionary<string, object>) //---------------------------------------按name名称循环
                {
                    string inputValue = request[item.Key]; //输入的值
                    foreach (var item1 in (Dictionary<string, object>) item.Value)
                        //-----------------------------name名称中包含的验证
                    {
                        JArray ja;
                        switch (item1.Key)
                        {
                            case "required":
                                NotEmpty(inputValue,GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "email":
                                Email(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "url":
                                Url(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "equalTo":
                                EqualTo(inputValue, request[item1.Value.ToString().Substring(1)], GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "regex":
                                Regex(inputValue, item1.Value.ToString(), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "allChinese":
                                AllChinese(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "notequalTo":
                                NotEqualTo(inputValue, request[item1.Value.ToString().Substring(1)], GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "min":
                                Min(inputValue,Convert.ToDouble(item1.Value), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "max":
                                Max(inputValue, Convert.ToDouble(item1.Value), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "range":
                                //JObject jObj = JObject.Parse(item1.Value.ToString());
                                ja = JArray.Parse(item1.Value.ToString());
                                Range(inputValue, Convert.ToDouble(ja[0]), Convert.ToDouble(ja[1]), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "minlength":
                                MinLength(inputValue, Convert.ToInt32(item1.Value), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "maxlength":
                                MaxLength(inputValue, Convert.ToInt32(item1.Value), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "rangelength":
                                //JObject jObj = JObject.Parse(item1.Value.ToString());
                                ja = JArray.Parse(item1.Value.ToString());
                                RangeLength(inputValue, Convert.ToInt32(ja[0]), Convert.ToInt32(ja[1]), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "charMinlength":
                                CharMinLength(inputValue, Convert.ToInt32(item1.Value), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "charMaxlength":
                                CharMaxLength(inputValue, Convert.ToInt32(item1.Value), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "charRangelength":
                                //JObject jObj = JObject.Parse(item1.Value.ToString());
                                ja = JArray.Parse(item1.Value.ToString());
                                CharRangeLength(inputValue, Convert.ToInt32(ja[0]), Convert.ToInt32(ja[1]), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "isIdCardNo":
                                IsIdCardNo(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "date":
                                Date(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "dateTime":
                                DateTime(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "dateTimeOrDate":
                                DateTimeOrDate(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "digits":
                                Digits(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "number":
                                Number(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "isIP":
                                IsIp(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "noHtml":
                                NoHtml(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "noChinese":
                                NoChinese(inputValue, GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                            case "notRegex":
                                NotRegex(inputValue, item1.Value.ToString(), GetMessage(item.Key));
                                if (!Checked) return false; //第一次失败则不向下执行。
                                break;
                        }
                    }
                }
            }
            return Checked;
        }
        /// <summary>
        /// 获取相对应的提示
        /// </summary>
        /// <param name="inputName">要验证的名称</param>
        /// <returns></returns>
        private string GetMessage(string inputName)
        {
            string message = null;
            if (DataValidate.Opts.ContainsKey("messages"))
            {
                if ((DataValidate.Opts["messages"] as Dictionary<string, object>).ContainsKey(inputName))
                {
                    message = (DataValidate.Opts["messages"] as Dictionary<string, object>)[inputName].ToString();
                }
            }
            return message;
        }

        #region 所有服务器端验证方法

        /// <summary>不能为空</summary>
        public bool NotEmpty(string inputValue,string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 必须为Email地址
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool Email(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsEmail())
                AddErrStr(message);
            return false;
        }
        /// <summary>
        /// 符合正则表达式
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="regex">正则表达式</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool Regex(string inputValue,string regex, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsMatchRegex(regex))
                AddErrStr(message);
            return false;
        }
        /// <summary>
        /// 全是中文
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool AllChinese(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsAllChinese())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 与另一个控件值相等
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="equalElement">比较值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool EqualTo(string inputValue, string equalElement, string message)
        {
            if (inputValue!=equalElement)
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 与另一个控件值不等
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="equalElement">比较值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool NotEqualTo(string inputValue, string equalElement, string message)
        {
            if (inputValue == equalElement)
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 不能小于最小值
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="num">最小值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool Min(string inputValue, double num, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.ToDouble() < num)
                AddErrStr(message);
            return false;
        }

        public bool Range(string inputValue, double min, double max, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.ToDouble()<min||inputValue.ToDouble()>max)
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 不能大于最大值
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="num">最大值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool Max(string inputValue, double num, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.ToDouble() > num)
                AddErrStr(message);
            return false;
        }

        #region 字符长度验证
        /// <summary>
        /// 长度不能小于（除去前后空格）
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="num">最小长度</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool MinLength(string inputValue, int num, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.Trim().Length < num)
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 长度不能大于（除去前后空格）
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="num">最大长度</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool MaxLength(string inputValue, int num, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.Trim().Length > num)
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 长度区间（除去前后空格）
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="min">最小长度</param>
        /// <param name="max">最大长度</param>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool RangeLength(string inputValue, int min, int max, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.Trim().Length > max || inputValue.Trim().Length < min)
                AddErrStr(message);
            return false;
        }
        /// <summary>
        /// 长度不能小于（除去前后空格）(按字节)
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="num">最小长度</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool CharMinLength(string inputValue, int num, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.Trim().CharCodeLength() < num)
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 长度不能大于（除去前后空格）(按字节)
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="num">最大长度</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool CharMaxLength(string inputValue, int num, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.Trim().CharCodeLength() > num)
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 长度区间（除去前后空格）(按字节)
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="min">最小长度</param>
        /// <param name="max">最大长度</param>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool CharRangeLength(string inputValue, int min, int max, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.Trim().CharCodeLength() > max || inputValue.Trim().CharCodeLength() < min)
                AddErrStr(message);
            return false;
        } 
        #endregion

        /// <summary>
        /// 身份证号码验证
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool IsIdCardNo(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsIdCard())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 日期验证
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool Date(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsDate())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 日期时间验证
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool DateTime(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsDateTime())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 日期时间验证
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool DateTimeOrDate(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsDateTimeOrDate())
                AddErrStr(message);
            return false;
        }
        /// <summary>
        /// 网址验证
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public new bool Url(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsUrlAddress())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 数字验证（可小数）
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool Number(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsNumber())
                AddErrStr(message);
            return false;
        }
        /// <summary>
        /// 整数验证
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool Digits(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsDigits())
                AddErrStr(message);
            return false;
        }
        /// <summary>
        /// IP地址验证
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool IsIp(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsHasHtml())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 不包含HTML代码
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool NoHtml(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsHasHtml())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 不包含中文或全角字符
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool NoChinese(string inputValue, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (!inputValue.IsHasChinese())
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// 非正则表达式，即不匹配正则
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="regex">正则表达式</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool NotRegex(string inputValue, string regex, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.IsMatchRegex(regex))
                AddErrStr(message);
            return false;
        }

        /// <summary>
        /// Char最大长度
        /// </summary>
        /// <param name="inputValue">输入值</param>
        /// <param name="num">正则表达式</param>
        /// <param name="message">提示</param>
        /// <returns></returns>
        public bool CharCodeLength(string inputValue, int num, string message)
        {
            if (string.IsNullOrWhiteSpace(inputValue))
                return false;
            if (inputValue.CharCodeLength()>num)
                AddErrStr(message);
            return false;
        }

        //DOTO 此方法未完成。以后完成
        //public bool MyRemote(string inputValue, string url, string message)
        //{
        //    if (false)
        //        AddErrStr(message);
        //    return false;
        //}
        #endregion


        /// <summary>添加服务端的错误信息</summary>
        private void AddErrStr(string message)
        {
            ErrStr += message;
            Checked = false;
        }

    }
}
